package edu.gatech.ealf.magiclenseplaf;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.LayoutManager;
import java.awt.Point;

import javax.swing.JComponent;

import edu.gatech.ealf.EasyAccessibilityLookAndFeel;
import edu.gatech.ealf.GlassPaneManager;

public class ZoomHelper {

    public JComponent curComponent = null;
    public Container originalContainer = null;
    private Font originalFont = null;
    private Container glass = null;
    private PlaceholderComponent placeholder = null;
    private int oldWidth = -1;
    private int oldHeight = -1;
    private Object layoutConstraint = null;
    private LayoutManager originalContainerLayout = null;
    private int componentIndex = -1;
    private boolean isZoomed = false;
    private boolean zoomable = true;
    private boolean ignoreScrollPane = false;
    
    public ZoomHelper(JComponent component){
        curComponent = component;
    }
    
    public ZoomHelper(JComponent component, boolean ignoreScrollPane){
        this(component);
        this.ignoreScrollPane = ignoreScrollPane;
    }
    
    public void zoom(){
        lazyLoad();
        if(isZoomed || !zoomable /*|| (!ignoreScrollPane && EasyAccessibilityLookAndFeel.isContainedBy(curComponent, "JScrollPane"))*/){
            return;
        }
        double zoomFactor = MagicLenseLookAndFeel.getInstance().getZoomFactor();
        if(placeholder == null){
            Dimension size = curComponent.getSize();
            placeholder = new PlaceholderComponent(size);
            placeholder.setAlignmentX(curComponent.getAlignmentX());
            placeholder.setAlignmentY(curComponent.getAlignmentY());
        }
        if(originalContainerLayout == null){
            originalContainerLayout = originalContainer.getLayout();
            if(originalContainerLayout instanceof BorderLayout){
                layoutConstraint = ((BorderLayout)originalContainerLayout).getConstraints(curComponent);
            }
        }
        originalFont = curComponent.getFont();
        componentIndex = EasyAccessibilityLookAndFeel.getComponentIndex(curComponent);
        Point absolutePosition = EasyAccessibilityLookAndFeel.getAbsolutePosition(curComponent);
        oldWidth = curComponent.getWidth();
        oldHeight = curComponent.getHeight();
        int newWidth = (int)(oldWidth * zoomFactor);
        int newHeight = (int)(oldHeight * zoomFactor);
        int newX = (absolutePosition.x + oldWidth/2) - (newWidth/2);
        int newY = (absolutePosition.y + oldHeight/2) - (newHeight/2);
        newX = Math.max(0, newX);
        newY = Math.max(0, newY);
        Dimension glassSize = glass.getSize();
        Font newFont = originalFont.deriveFont((float) zoomFactor * originalFont.getSize());
        if((newX + newWidth) > glassSize.width){
            newWidth = glassSize.width - newX;
            newFont = originalFont.deriveFont((float) ((float)newWidth / oldWidth) * originalFont.getSize());
        }
        //System.out.println((newY + newHeight) + ", " + glassSize.height);
        if((newY + newHeight) > glassSize.height){
            newHeight = glassSize.height - newY;
            newFont = originalFont.deriveFont((float) ((float)newHeight / oldHeight) * originalFont.getSize());
        }
        //System.out.println(newHeight);
        
        curComponent.setFont(newFont);
        glass.setLayout(null);
        glass.add(curComponent);
        originalContainer.add(placeholder, componentIndex);
        curComponent.setBounds(newX, newY, newWidth, newHeight);
        GlassPaneManager.registerComponentHome(curComponent, this);
        GlassPaneManager.show(glass, curComponent);
        isZoomed = true;
    }

    public void lazyLoad() {
        if(originalContainer == null){
            originalContainer = curComponent.getParent();
        }
        if(glass == null){
            if(curComponent.getRootPane() != null){
                glass = (Container) curComponent.getRootPane().getGlassPane();
                GlassPaneManager.register(glass, curComponent); 
            }
        }
    }
    
    public void unZoom(){
        unZoomSingle();
        if(glass != null){
            Component[] glassComps = glass.getComponents();
            for(Component comp : glassComps){
                ZoomHelper foreignZoomer = GlassPaneManager.unregisterComponentHome(comp);
                if(foreignZoomer != null){
                    foreignZoomer.unZoomSingle();
                }
            }
        }
    }

    private void unZoomSingle() {
        lazyLoad();
        if(!isZoomed){
            return;
        }
        originalContainer.remove(placeholder);
        glass.remove(curComponent);
        curComponent.setFont(originalFont);
        curComponent.setSize(oldWidth, oldHeight);
        if(originalContainerLayout instanceof BorderLayout){
            originalContainer.add(curComponent, layoutConstraint);
        } else {
            originalContainer.add(curComponent, componentIndex);
        }
        originalContainer.repaint();
        
        GlassPaneManager.hide(glass, curComponent);
        isZoomed = false;
    }
    
    public void destroy(){
        GlassPaneManager.unregister(glass, curComponent);
        placeholder = null;
        glass = null;
        originalFont = null;
        originalContainer = null;
        layoutConstraint = null;
    }
    
    public void setZoomable(boolean zoomable){
        this.zoomable = zoomable;
    }
    public boolean isZoomable(){
        return zoomable;
    }
    
    public void toggleZoomable(){
        zoomable = !zoomable;
        if(!zoomable){
            unZoom();
        } else {
            zoom();
        }
    }
    
}
